package demo.topic16;

import demo.topic15.Color;
import org.junit.Test;

import java.lang.reflect.Method;

/**
 * 注解
 *
 * 1. 认识Annotation：JDK1.5开始，Java增加了对元数据（即类的组成单元数据）的支持，也就是（Annotation）注解，他是代码里做的特殊标记，
 * 这些标记可以在编译、类加载、运行时在不改变原有逻辑的情况下，被读取，并执行相应的处理，通过使用Annotation，程序员可以在源文件中嵌入一些
 * 补充的信息。代码分析工具，开发工具和部署工具可以通过这些补充信息进行验证或者进行部署。Annotation类似于修饰符一样被使用，可以用于包、类、
 * 构造方法、方法、成员变量、参数、局部变量的声明。
 * （注意：Annotation是一个接口，java.lang.Annotation接口！！！）
 *
 * 2. 系统定义的Annotation：在JDK1.5之后，在系统重提供了三个Annotation，分别是@Override、@Deprecated、@SuppressWarnings。
 * （1）@Override：重写方法
 * （2）@Deprecated：类或方法已过时
 * （3）@SuppressWarnings：消除警告
 * （3.1）SuppressWarnings("unchecked")：未检查的转化，如集合没有指定类型
 * （3.2）SuppressWarnings("unused")：未使用的变量
 * （3.3）SuppressWarnings("resource")：有泛型未指定类型
 * （3.4）SuppressWarnings("path")：在类路径，原文件路径中有不存在的路径
 * （3.5）SuppressWarnings("deprecation")：使用了某些不赞成使用的类和方法
 * （3.6）SuppressWarnings("fallthrough")：switch语句执行到底没有break关键字
 * （3.7）SuppressWarnings("serial")：某类实现Serializable，但是没有定义serialVersionUID这个需要但是不必须的字段
 * （3.8）SuppressWarnings("rawtypes")：没有传递带有泛型的参数
 * （3.9）SuppressWarnings("all")：全部类型的警告
 *
 */
public class AnnotationDemo {

    /**
     * 反射处理自定义注解
     * 读取注解信息
     */
    @Test
    public void test1() {
        Class<Cat> catClass = Cat.class;
        // 获取类上应用的指定注解
        ClassAnnotation annotation = catClass.getAnnotation(ClassAnnotation.class);
        // 获取注解上变量值
        String name = annotation.name();
        int age = annotation.age();
        Color color = annotation.color();
        String[] like = annotation.like();

        Cat cat = null;
        try {
            cat = catClass.newInstance();
            cat.setName(name);
            cat.setAge(age);
            cat.setColor(color);
            cat.setLike(like);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        System.out.println(cat.toString()); // Cat{name='小橘猫', age=1, color=YELLOW, like=[鱼, 鸡腿, 猫粮]}
    }

    /**
     * 反射获取注解
     */
    @Test
    public void test2() {
        try {
            Class<?> aClass = Class.forName("demo.topic16.Cat");
            Method setName = aClass.getMethod("setName", String.class);
            System.out.println(setName); // public void demo.topic16.Cat.setName(java.lang.String)
            System.out.println(setName.isAnnotationPresent(MethodAnnotation.class)); // true
            if (setName.isAnnotationPresent(MethodAnnotation.class)) {
                MethodAnnotation annotation = setName.getAnnotation(MethodAnnotation.class);
                System.out.println(annotation); // @demo.topic16.MethodAnnotation()
            }
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }
}
